﻿
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace DbUp.ScriptProviders
{
    ///<summary>
    /// Basic base class for a sql change script.
    ///</summary>
    public abstract class SqlScriptVersion
    {
        protected SqlScriptVersion(Guid versionKey, string name)
        {
            VersionKey = versionKey;
            Name = name;
        }

        /// <summary>
        /// Gets the name of the script.
        /// </summary>
        public string Name { get; private set; }

        ///<summary>
        /// Gets the versionKey of the script
        ///</summary>
        public Guid VersionKey { get; private set; }
    }


    /// <summary>
    /// Represents a SQL Server script that may be eligible for applying to a database.
    /// </summary>
    public sealed class SqlScript : SqlScriptVersion
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="SqlScript"/> class.
        /// </summary>
        /// <param name="versionKey">The Guid key identifier of the script.</param>
        /// <param name="name">The name.</param>
        /// <param name="contents">The contents.</param>
        public SqlScript(string name, string contents)
            : base(GetGuidFromScript(name, contents), name)
        {
            Contents = contents;
        }

        ///<summary>
        /// Will take the contents of a sql file and find the version key
        /// Format: "-- Version: {GUID}"
        ///</summary>
        ///<param name="contents"></param>
        ///<returns></returns>
        ///<exception cref="NoVersionKeyFoundException"></exception>
        public static Guid GetGuidFromScript(string name, string contents)
        {
            var versionLine = new Regex(@"Version:\s*(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})\s*^", RegexOptions.Multiline)
                .Match(contents)
                .Groups[0];

            var foundGuid = new Regex(@"(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})")
                    .Match(versionLine.Value)
                    .Value;

            if (string.IsNullOrEmpty(foundGuid))
                throw new NoVersionKeyFoundException(name);

            return new Guid(foundGuid);
        }

        /// <summary>
        /// Gets the contents of the script.
        /// </summary>
        /// <value></value>
        public string Contents { get; private set; }
    }

    ///<summary>
    /// Represents a version script that has already been applied to the database.
    ///</summary>
    public sealed class SqlScriptAlreadyApplied : SqlScriptVersion
    {
        ///<summary>
        /// The logged in user who applied the script.
        ///</summary>
        public string AppliedByUser { get; private set; }
        ///<summary>
        /// The date a change script was applied.
        ///</summary>
        public DateTime AppliedDate { get; private set; }
        ///<summary>
        /// The server name a script was applied on.
        ///</summary>
        public string ServerName { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="SqlScriptAlreadyApplied"/> class.
        /// </summary>
        /// <param name="versionKey">The Guid key identifier of the script.</param>
        /// <param name="name">The name.</param>
        ///<param name="appliedByUser">The logged in person who applied an existing script.</param>
        ///<param name="appliedDate">The date a script was applied.</param>
        ///<param name="serverName">The server the script was applied on.</param>
        public SqlScriptAlreadyApplied(Guid versionKey, string name, string appliedByUser, DateTime appliedDate, string serverName)
            : base(versionKey, name)
        {
            AppliedByUser = appliedByUser;
            AppliedDate = appliedDate;
            ServerName = serverName;
        }
    }

}